/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.pro.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.jni.FileInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.bom.entity.Bom;
import vip.xiaonuo.modular.bom.service.BomService;
import vip.xiaonuo.modular.fieldconfig.entity.FieldConfig;
import vip.xiaonuo.modular.fieldconfig.service.FieldConfigService;
import vip.xiaonuo.modular.invdetail.entity.InvDetail;
import vip.xiaonuo.modular.invdetail.service.InvDetailService;
import vip.xiaonuo.modular.pro.entity.Pro;
import vip.xiaonuo.modular.pro.enums.ProExceptionEnum;
import vip.xiaonuo.modular.pro.mapper.ProMapper;
import vip.xiaonuo.modular.pro.param.ProParam;
import vip.xiaonuo.modular.pro.result.ProPageResult;
import vip.xiaonuo.modular.pro.service.ProService;
import vip.xiaonuo.modular.promodel.entity.ProModel;
import vip.xiaonuo.modular.promodel.service.ProModelService;
import vip.xiaonuo.modular.protype.service.ProTypeService;
import vip.xiaonuo.modular.puordetail.entity.PuorDetail;
import vip.xiaonuo.modular.puordetail.service.PuorDetailService;
import vip.xiaonuo.modular.task.entity.Task;
import vip.xiaonuo.modular.workorder.entity.WorkOrder;
import vip.xiaonuo.modular.workorder.param.WorkOrderParam;
import vip.xiaonuo.modular.workorder.service.WorkOrderService;
import vip.xiaonuo.modular.workroute.service.WorkRouteService;
import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
import vip.xiaonuo.util.AutoCode;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 产品表service接口实现类
 *
 * @author 李
 * @date 2022-05-20 11:51:12
 */
@Service
public class ProServiceImpl extends ServiceImpl<ProMapper, Pro> implements ProService {
    @Resource
    ProTypeService proTypeService;

    @Resource
    ProModelService proModelService;

    @Resource
    BomService bomService;

    @Resource
    InvDetailService invDetailService;

    @Resource
    PuorDetailService puorDetailService;

    @Resource
    WorkOrderService workOrderService;

    @Resource
    SysFileInfoService sysFileInfoService;

    @Resource
    private FieldConfigService fieldConfigService;

    @Override
    public PageResult<ProPageResult> page(ProParam proParam) {
        //sql表名，作为sql语句的一部分
        final String sqlTableName = "n.pro_type_id";
        QueryWrapper<ProPageResult> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(proParam)) {
            // 根据产品编码 查询
            if (ObjectUtil.isNotEmpty(proParam.getCode())) {
                queryWrapper.like("n.code", proParam.getCode());
            }
            // 根据产品名称 查询
            if (ObjectUtil.isNotEmpty(proParam.getName())) {
                queryWrapper.like("n.name", proParam.getName());
            }
            // 根据产品类型 查询
            if (ObjectUtil.isNotEmpty(proParam.getProTypeId())) {
                List<Long> childIdList = proTypeService.getChildIdListById(proParam.getProTypeId());
                if (!childIdList.isEmpty()) {
                    queryWrapper.nested(item -> item.eq(sqlTableName, proParam.getProTypeId()).or().in(sqlTableName, childIdList));
                } else {
                    queryWrapper.eq(sqlTableName, proParam.getProTypeId());
                }

            }
            // 根据备注 查询
            if (ObjectUtil.isNotEmpty(proParam.getRemarks())) {
                queryWrapper.like("n.remarks", proParam.getRemarks());
            }
//            //根据动态字段 查询
//            if (ObjectUtil.isNotEmpty(proParam.getJosn())) {
//                Map<String, Object> map = JSON.parseObject((String) proParam.getJosn(), HashMap.class);
//                for (Map.Entry<String, Object> entry : map.entrySet()) {
//                    if (ObjectUtil.isNotEmpty(entry.getValue())) {
//                        queryWrapper.apply("n.josn->" + "'$." + entry.getKey() + "'" + "like" + "'%" + entry.getValue() + "%'");
//                    }
//                }
//            }

            // 根据字段扩展 查询
            if (ObjectUtil.isNotEmpty(proParam.getJosn())) {
                //调用动态字段查询方法
                dynamicFieldQuery("dw_pro", queryWrapper,proParam.getJosn());
            }
        }
        queryWrapper.orderByDesc("n.create_time");
        return new PageResult<>(this.baseMapper.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<Pro> list(ProParam proParam) {
        return this.list();
    }

    @Override
    public void add(ProParam proParam) {
        final String code = proParam.getCode();
        if (ObjectUtil.isNull(code) || ObjectUtil.isEmpty(code)) {
            proParam.setCode(AutoCode.getCodeByService("dw_pro", this.getClass(), 0));
            Console.log(proParam.getCode());
        }
        //校验参数，检查是否存在相同的名称和编码
        checkParam(proParam, false);
        //将json转换为json字符串
        String josnToString = JSON.toJSON(proParam.getJosn()).toString();
        proParam.setJosn(josnToString);
        //参数copy到实体类中进行保存
        Pro pro = new Pro();
        BeanUtil.copyProperties(proParam, pro);
        this.save(pro);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<ProParam> proParamList) {
        // TODO 删除校验
        verifiDelete(proParamList);
        QueryWrapper<ProModel> queryWrapper = new QueryWrapper<>();
        QueryWrapper<Pro> proQueryWrapper = new QueryWrapper<>();
        QueryWrapper<SysFileInfo> sysQueryWrapper = new QueryWrapper<>();
        List<ProModel> proModelList = proModelService.list(queryWrapper);
        proParamList.forEach(proParam -> {
            //调用方法，根据id查询当前产品数据
            Pro pro = this.getById(proParam.getId());
            if (ObjectUtil.isNull(pro)) {
                throw new ServiceException(5, "【" + pro.getName() + "】" + "产品不存在");
            }
            Long id = pro.getId();
            //同时删掉报工表
            proQueryWrapper.lambda().eq(Pro::getId, proParam.getId()).or();
            //根据产品的图片id查找文件id
            sysQueryWrapper.lambda().eq(SysFileInfo::getId,pro.getImage()).or();
            //根据产品id查询产品型号
            if (ObjectUtil.isNotEmpty(id)) {
                queryWrapper.lambda().eq(ProModel::getProId, id);
            }
            //如果该产品下存在型号，则不可删除
            if (!proModelList.isEmpty()) {
                throw new ServiceException(6, "【" + pro.getName() + "】下存在所属产品型号，不可删除！");
            }
            //删除图片

        });
        sysFileInfoService.remove(sysQueryWrapper);
        this.remove(proQueryWrapper);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(ProParam proParam) {
        //校验参数，检查是否存在相同的名称和编码
        checkParam(proParam, true);
        Pro pro = this.queryPro(proParam);
        BeanUtil.copyProperties(proParam, pro);
        //将js值转换为Josn字符串
        if (ObjectUtil.isNotEmpty(proParam.getJosn())) {
            String josnToString = JSON.toJSON(proParam.getJosn()).toString();
            pro.setJosn(josnToString);
        } else {
            pro.setJosn(pro.getJosn().toString());
        }
        //修改
        this.updateById(pro);
    }

    @Override
    public Pro detail(ProParam proParam) {
        return this.queryPro(proParam);
    }


    /**
     * 获取产品表
     *
     * @author 李
     * @date 2022-05-20 11:51:12
     */
    private Pro queryPro(ProParam proParam) {
        Pro pro = this.getById(proParam.getId());
        if (ObjectUtil.isNull(pro)) {
            throw new ServiceException(ProExceptionEnum.NOT_EXIST);
        }
        return pro;
    }

    @Override
    public void export(ProParam proParam) {
        List<Pro> list = this.list(proParam);
        PoiUtil.exportExcelWithStream("SnowyPro.xls", Pro.class, list);
    }


    /**
     * 校验参数，检查是否存在相同的名称和编码
     *
     * @author xuyuxiang
     * @date 2020/3/25 21:23
     */
    private void checkParam(ProParam proParam, boolean isExcludeSelf) {
        Long id = proParam.getId();
        String name = proParam.getName();
        String code = proParam.getCode();

        LambdaQueryWrapper<Pro> queryWrapperByName = new LambdaQueryWrapper<>();
        queryWrapperByName.eq(Pro::getName, name);

        LambdaQueryWrapper<Pro> queryWrapperByCode = new LambdaQueryWrapper<>();
        queryWrapperByCode.eq(Pro::getCode, code);
        //如果是编辑，校验名称编码时排除自身
        if (isExcludeSelf) {
            queryWrapperByName.ne(Pro::getId, id);
            queryWrapperByCode.ne(Pro::getId, id);
        }

        int countByName = this.count(queryWrapperByName);
        int countByCode = this.count(queryWrapperByCode);

        if (countByName >= 1) {
            throw new ServiceException(3, "产品名称重复，请检查名称参数");
        }
        if (countByCode >= 1) {
            throw new ServiceException(4, "产品编码重复，请检查编码参数");
        }
    }

    /**
     * 删除校验
     *
     * @author xuyuxiang
     * @date 2020/3/25 21:23
     */
    private void verifiDelete(List<ProParam> proParamList) {

        List<Long> proIds = new ArrayList<Long>();
        proParamList.forEach(proParam -> {
            proIds.add(proParam.getId());
        });
        //物料清单校验
        QueryWrapper<Bom> bomQueryWrapper = new QueryWrapper<>();
        bomQueryWrapper.lambda().in(Bom::getParentId, proIds).or().in(Bom::getSubitemId, proIds);
        int bomCount = bomService.count(bomQueryWrapper);
        if (bomCount >= 1) {
            throw new ServiceException(7, "已有产品绑定物料清单，请先删除物料清单");
        }
        //仓库明细校验
        QueryWrapper<InvDetail> iqw = new QueryWrapper<>();
        iqw.lambda().in(InvDetail::getProId, proIds);
        int invDetailCount = invDetailService.count(iqw);
        if (invDetailCount >= 1) {
            throw new ServiceException(8, "仓库管理存在该些产品，请先清空产品所在的仓库");
        }
        //采购明细校验
        QueryWrapper<PuorDetail> pqw = new QueryWrapper<>();
        pqw.lambda().in(PuorDetail::getProId, proIds);
        int puorDetailCount = puorDetailService.count(pqw);
        if (puorDetailCount >= 1) {
            throw new ServiceException(9, "采购明细存在该些产品，请先检查采购明细");
        }
        //工单校验
        QueryWrapper<WorkOrder> wqw = new QueryWrapper<>();
        wqw.lambda().in(WorkOrder::getProId, proIds);
        int workOrderCount = workOrderService.count(wqw);
        if (workOrderCount >= 1) {
            throw new ServiceException(10, "工单中存在该产品，请先检查工单");
        }
    }

    /**
     * 添加动态字段查询条件
     */
    @Override
    public <T> void dynamicFieldQuery(String tableName, QueryWrapper<T> queryWrapper, Object josn) {
        /*
         * ===============================================添加查询条件前准备工作 start ======================================
         */
        //定义hashMap
        Map<String, String> fieldConfigMap = new HashMap<>();
        //构造表名为查询条件
        QueryWrapper<FieldConfig> queryWrapperByFieldConfig = new QueryWrapper<>();
        queryWrapperByFieldConfig.lambda().eq(FieldConfig::getTableName, tableName);
        List<FieldConfig> fieldConfig = fieldConfigService.list(queryWrapperByFieldConfig);
        //将配置字段数据保存为HashMap，字段索引为key，字段类型为value
        fieldConfig.forEach(item -> fieldConfigMap.put(item.getFieldIndex(), item.getFieldType()));
        //将json转换为map
        Map<String, Object> map = JSON.parseObject((String) josn, HashMap.class);

        /*
         * ===============================================添加查询条件前准备工作 end ======================================
         */
        //为动态字段添加查询条件
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            //避免value值为空并判断字段类型
            if (ObjectUtil.isNotEmpty(entry.getValue()) && StringUtils.equals(fieldConfigMap.get(entry.getKey()), "string")) {

                queryWrapper.apply("n.josn->" + "'$." + "\""+ entry.getKey() + "\""+ "'" + "like" + "'%" + entry.getValue() + "%'");
            }
            if (ObjectUtil.isNotEmpty(entry.getValue()) && StringUtils.equals(fieldConfigMap.get(entry.getKey()), "date")) {

                queryWrapper.apply("n.josn->" + "'$." + "\""+ entry.getKey() + "\""+ "'" + "=" +"\""+ entry.getValue() +"\"");
            }
            if (ObjectUtil.isNotEmpty(entry.getValue()) && StringUtils.equals(fieldConfigMap.get(entry.getKey()), "number")) {
                queryWrapper.apply("n.josn->" + "'$."+ "\"" + entry.getKey()+ "\"" + "'" + "=" + entry.getValue());
            }
        }

    }

}